package com.lucene;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.junit.Test;
import org.wltea.analyzer.lucene.IKAnalyzer;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.stream.Stream;

/**
 * 索引搜索
 *
 * @author HuTongFu
 * @since 2018/1/3
 */
public class IndexSearchTest {


    /**
     * QueryParser 查询 只能查询文本类型的
     *
     * @throws IOException
     * @throws ParseException
     */
    @Test
    public void indexSearchTest() throws IOException, ParseException {

        //创建分词器，StandardAnalyzer标准分词器，对中文是单字分词，对英文分词效果很好
        //Analyzer analyzer = new StandardAnalyzer();
        //创建分词器，IKAnalyzer中文分词器
        Analyzer analyzer = new IKAnalyzer();
        //指定索引和文档的目录
        Directory directory = FSDirectory.open(new File("D:\\workspace\\lucene\\writer"));

        //创建索引和文档的读取对象
        IndexReader indexReader = IndexReader.open(directory);
        //创建索引的搜索对象
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);
        //创建查询语句对象。第一个参数【默认搜索域】、第二个参数【分词器】
        QueryParser queryParser = new QueryParser("fileName", analyzer);
        //查询语法=域名：搜索的关键字
        Query query = queryParser.parse("fileName:test");

        //搜索。第一个参数【查询语句对象】、第二个参数【指定显示多少条】
        TopDocs topDocs = indexSearcher.search(query, 5);
        //
        System.out.println("一共搜索到" + topDocs.totalHits + "条记录");
        //从搜索结果对象中获取结果集
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;

        Stream.of(scoreDocs).forEach(scoreDoc -> {
            //获取docID【此docID是由lucene 自动生成的】
            int docID = scoreDoc.doc;
            //通过文档Id从硬盘中读取出对应的文档
            try {
                Document document = indexReader.document(docID);
                //get域名可以取出值打印
                System.out.println("fileName:" + document.get("fileName"));
                System.out.println("fileContext:" + document.get("fileContext"));
                System.out.println("fileSize:" + document.get("fileSize"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * TermQuery 查询 也可以查询文本类型
     */
    @Test
    public void termQueryTest() throws IOException {

        //创建分词器，IKAnalyzer分词器
        Analyzer analyzer = new IKAnalyzer();

        //指定索引和文档的目录
        Directory directory = FSDirectory.open(new File("D:\\workspace\\lucene\\writer"));

        //创建索引和文档读对象
        IndexReader indexReader = IndexReader.open(directory);
        //创建索引的搜索对象
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);

        //创建词元，也就是词
        Term term = new Term("fileName", "test");
        //创建TermQuery
        TermQuery termQuery = new TermQuery(term);

        TopDocs topDocs = indexSearcher.search(termQuery, 5);
        System.out.println("一共搜索到" + topDocs.totalHits + "条记录");
        //从搜索结果对象中获取结果集
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        Arrays.stream(scoreDocs).forEach(scoreDoc -> {
            //获取docID【此docID是由lucene 自动生成的】
            int docID = scoreDoc.doc;
            //通过文档Id从硬盘中读取出对应的文档
            Document document = null;
            try {
                document = indexReader.document(docID);
                //get域名可以取出值打印
                System.out.println("fileName:" + document.get("fileName"));
                System.out.println("fileContext:" + document.get("fileContext"));
                System.out.println("fileSize:" + document.get("fileSize"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * NumericRangeQuery 查询 用来查询数值类型的
     */
    @Test
    public void numericRangeQueryTest() throws IOException {
        //创建分词器，IKAnalyzer分词器
        Analyzer analyzer = new IKAnalyzer();

        //指定索引和文档的目录
        Directory directory = FSDirectory.open(new File("D:\\workspace\\lucene\\writer"));

        //创建索引和文档读对象
        IndexReader indexReader = IndexReader.open(directory);
        //创建索引的搜索对象
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);

        //根据数字范围查询
        //第一个参数：域名，第二个参数：最小值，第三个参数：最大值，第四个参数：是否包含最小值，第五个参数：是否包含最大值
        Query query = NumericRangeQuery.newLongRange("fileSize", 24L, 500L, false, true);

        TopDocs topDocs = indexSearcher.search(query, 5);

        System.out.println("一共搜索到" + topDocs.totalHits + "记录");
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;

        Arrays.stream(scoreDocs).forEach(scoreDoc -> {
            int docId = scoreDoc.doc;
            try {
                Document document = indexReader.document(docId);
                System.out.println("fileName:" + document.get("fileName"));
                System.out.println("fileContext:" + document.get("fileContext"));
                System.out.println("fileSize:" + document.get("fileSize"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        });

    }

    /**
     * BooleanQuery 查询 组合查询
     */
    @Test
    public void booleanQueryTest() throws IOException {
        //创建分词器，IKAnalyzer分词器
        Analyzer analyzer = new IKAnalyzer();

        //指定索引和文档的目录
        Directory directory = FSDirectory.open(new File("D:\\workspace\\lucene\\writer"));

        //创建索引和文档读对象
        IndexReader indexReader = IndexReader.open(directory);
        //创建索引的搜索对象
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);

        //多条件查询
        BooleanQuery query = new BooleanQuery();

        //根据数字范围查询
        //第一个参数：域名，第二个参数：最小值，第三个参数：最大值，第四个参数：是否包含最小值，第五个参数：是否包含最大值
        Query numericRangeQuery = NumericRangeQuery.newLongRange("fileSize", 24L, 500L, true, true);

        //创建词元，也就是词
        Term term = new Term("fileName", "test");
        //创建TermQuery
        TermQuery termQuery = new TermQuery(term);

        //Occur是逻辑条件
        //must相当于and关键字，should相当于or关键字，must_not相当于not关键字
        //注：单独使用must_not 是没有任何意义的
        query.add(numericRangeQuery, BooleanClause.Occur.MUST);
        query.add(termQuery, BooleanClause.Occur.MUST);

        TopDocs topDocs = indexSearcher.search(query, 5);

        System.out.println("一共搜索到" + topDocs.totalHits + "记录");
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;

        Arrays.stream(scoreDocs).forEach(scoreDoc -> {
            int docId = scoreDoc.doc;
            try {
                Document document = indexReader.document(docId);
                System.out.println("fileName:" + document.get("fileName"));
                System.out.println("fileContext:" + document.get("fileContext"));
                System.out.println("fileSize:" + document.get("fileSize"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * MatchAllDocsQuery 查询 查询所有文档
     */
    @Test
    public void matchAllDocsQueryTest() throws IOException {
        //创建分词器，IKAnalyzer分词器
        Analyzer analyzer = new IKAnalyzer();

        //指定索引和文档的目录
        Directory directory = FSDirectory.open(new File("D:\\workspace\\lucene\\writer"));

        //创建索引和文档读对象
        IndexReader indexReader = IndexReader.open(directory);
        //创建索引的搜索对象
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);

        //查询所有文档
        MatchAllDocsQuery query = new MatchAllDocsQuery();

        TopDocs topDocs = indexSearcher.search(query, 5);

        System.out.println("一共搜索到" + topDocs.totalHits + "记录");
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;

        Arrays.stream(scoreDocs).forEach(scoreDoc -> {
            int docId = scoreDoc.doc;
            try {
                Document document = indexReader.document(docId);
                System.out.println("fileName:" + document.get("fileName"));
                System.out.println("fileContext:" + document.get("fileContext"));
                System.out.println("fileSize:" + document.get("fileSize"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }


    /**
     * MultiFieldQuery 查询
     */
    @Test
    public void multiFieldQueryTest() throws IOException, ParseException {
        //创建分词器，IKAnalyzer分词器
        Analyzer analyzer = new IKAnalyzer();

        //指定索引和文档的目录
        Directory directory = FSDirectory.open(new File("D:\\workspace\\lucene\\writer"));

        //创建索引和文档读对象
        IndexReader indexReader = IndexReader.open(directory);
        //创建索引的搜索对象
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);

        String[] fields = {"fileName", "fileContext"};
        MultiFieldQueryParser multiFieldQueryParser = new MultiFieldQueryParser(fields, analyzer);
        Query query = multiFieldQueryParser.parse("test1");

        TopDocs topDocs = indexSearcher.search(query, 5);

        System.out.println("一共搜索到" + topDocs.totalHits + "记录");
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;

        Arrays.stream(scoreDocs).forEach(scoreDoc -> {
            int docId = scoreDoc.doc;
            try {
                Document document = indexReader.document(docId);
                System.out.println("fileName:" + document.get("fileName"));
                System.out.println("fileContext:" + document.get("fileContext"));
                System.out.println("fileSize:" + document.get("fileSize"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }
}
